package typechecker.walkers;

import typechecker.Stage;
import typechecker.ast.type.ForallType;
import typechecker.ast.type.FunctionType;
import typechecker.ast.type.TypeConstructor;
import typechecker.ast.type.TypeConstructorApplication;
import typechecker.ast.type.TypeExpression;
import typechecker.ast.type.TypeVariable;

/**
 * Walker to instantiate the "template" stage variable with
 * the supplied stage variable. 
 */
public class InstConstructorType {

	private static void instConstructorApplication(
			TypeConstructorApplication te, Stage alpha) {

		TypeConstructor tc = te.getCons();
		Stage old = tc.getStage();

		/* Base variable of the stage is replaced with the fresh one */
		if( Stage.TEMPLATE_VAR_NAME.equals(old.getBaseVar())){
			tc.setStage(new Stage(alpha.getBaseVar(), alpha.getSucc() + old.getSucc()));
		}		
	}

	private static void instFunctionType(FunctionType te, Stage alpha) {
		inst(te.getSrc(), alpha);
		inst(te.getDest(), alpha);
	}

	private static void instForallType(ForallType te, Stage alpha) {
		inst(te.getBody(), alpha);
	}

	private  static void instVariable(TypeVariable te, Stage alpha) {
	}

	public static void inst(TypeExpression te, Stage alpha){
		if (te instanceof ForallType){
			instForallType((ForallType)te, alpha);
		} else if ( te instanceof FunctionType){
			instFunctionType((FunctionType)te, alpha);
		} else if ( te instanceof TypeConstructorApplication){
			instConstructorApplication((TypeConstructorApplication) te, alpha);
		} else if ( te instanceof TypeVariable){
			instVariable((TypeVariable)te, alpha);
		}
	}
}
